package com.sf.aspectLog.autoconfiguration;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;


/**
 * @Author :Mr 轩少
 * @Date:2020/5/7
 * @Description:
 */

@Aspect
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class AspectLogAutoConfiguration {
    private Logger logger =  LoggerFactory.getLogger(getClass());
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) ")
    private  void getMapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping) ")
    private  void postMapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.Mapping) ")
    private  void mapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping) ")
    private  void putMapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PatchMapping) ")
    private  void patchMapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.DeleteMapping) ")
    private  void deleteMapping(){}
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) ")
    private  void requestMapping(){}

    @Autowired
    ConfigurableEnvironment environment;

    @Around("getMapping() ||postMapping()||mapping()||putMapping()||" +
            "patchMapping()|| deleteMapping()||requestMapping()")
    public Object print(ProceedingJoinPoint thisJoinPoint)
            throws Throwable {
        String appName = environment.getProperty("spring.application.name");
        boolean aspectLogOn = hasAnnotation( thisJoinPoint);
        if(aspectLogOn){
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert attributes != null;
            HttpServletRequest request = attributes.getRequest();
            ReqeustData build = ReqeustData.builder().setIP(request.getRemoteAddr())
                    .setHttpMethod(request.getMethod()).setUrl(request.getRequestURL().toString())
                    .setRequestBody(thisJoinPoint).setRequestParams(request.getParameterMap()).build();
            logger.info("【REQUEST】-->APPLICATION_NAME：{}，SIGNATURE：{},DATA:{}",appName,thisJoinPoint.getSignature().toString(),build);

        }
        long time = System.currentTimeMillis();
        Object result = thisJoinPoint.proceed();
        if(aspectLogOn){
            logger.info("【RESPONSE】--->APPLICATION_NAME：{}，SIGNATURE：{},RESULT:{} RUN :{} ms",appName,thisJoinPoint.getSignature().toString(), JSON.toJSONString(result),
                    (System.currentTimeMillis() - time));
        }

        return result;
    }

    private boolean hasAnnotation(ProceedingJoinPoint proceedingJoinPoint) {
        MethodSignature signature = (MethodSignature) (proceedingJoinPoint.getSignature());
        Class declaringType =signature.getDeclaringType();
        Method method = signature.getMethod();
        if(declaringType.isAnnotationPresent(AspectLog.class)||method.isAnnotationPresent(AspectLog.class)){
            return true;
        }
       return false;
    }

}
